#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "visualizer.h"
#include "minSphere.h"
#include "glut_trackball.h"
#ifdef MACOS
#include <glut.h>
#else
#include <GL/glut.h>
#endif
#include <AntTweakBar.h>



#define W 800
#define H 600


Visualizer *visualizer;
int tw_my_var = 0;

void display ()
{
    visualizer->paintGL ();
    TwDraw ();

    glFlush ();
    glutSwapBuffers ();
}

void reshape (int w, int h)
{
    visualizer->resizeGL (w, h);
    TwWindowSize (w, h);
    glutPostRedisplay ();
}

void mouse_click (int button, int state, int x, int y)
{
    //printf ("%d\n", tw_my_var);
    //printf ("b: %d s: %d x: %d y: %d\n", button, state, x, y);
    if (TwEventMouseButtonGLUT (button, state, x, y))
    {
         glutPostRedisplay ();
        return;
    }

    if ((button == WHEEL_UP || button == WHEEL_DOWN) && state == GLUT_DOWN)
    {
        visualizer->mouseWheel ((button == WHEEL_UP)? 1 : -1, GLUT2VCG (button));
        return;
    }

    if (state == GLUT_DOWN)
        visualizer->mousePress (x, y, GLUT2VCG (button));

    if (state == GLUT_UP)
        visualizer->mouseRelease (x, y, GLUT2VCG (button));

    glutPostRedisplay ();
}

void mouse_move (int x, int y)
{
    if (TwEventMouseMotionGLUT (x, y))
    {
         glutPostRedisplay ();
        return;
    }

    visualizer->mouseMove (x, y);

    glutPostRedisplay ();
}

void keyboard (unsigned char k, int x, int y)
{
    TwEventKeyboardGLUT (k, x, y);
    glutPostRedisplay ();
}

void special (int k, int x, int y)
{
    TwEventSpecialGLUT (k, x, y);
    glutPostRedisplay ();
}

void TW_CALL doTopologicQuery (void *clientData)
{
    visualizer->launchSphereBreadthQuery ();
}

void TW_CALL doSpaceQuery (void *clientData)
{
    visualizer->launchSphereSpaceQuery ();
}

void TW_CALL doStructureQuery (void *clientData)
{
    visualizer->launchSphereStructureQuery();
}

void TW_CALL setFactor (const void *value, void *clientData)
{
    visualizer->setSphereRadius (*(const float *) value);
}

void TW_CALL getFactor (void *value, void *clientData)
{
    *(float *)value = visualizer->scaledSphereRadius;;
}


int main(int argc, char *argv[])
{
    // Test for Miniball
    vector<Point3d> v;
    v.push_back(Point3d(0,0,0));
    v.push_back(Point3d(1,0,0));
    v.push_back(Point3d(2,0,0));

    MinSphere ms = MinSphere::computePoints (v);
    printf ("Miniball test, point interface:\n");
    cerr << "  Radius: " << ms.radius << endl;
    cerr << "  Center: " << ms.center[0] << " " << ms.center[1] << " " << ms.center[2] << endl;
    printf ("-----------\n\n");

    //return 0;

    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize (W, H);
    glutCreateWindow ("visualizer");

    if (argc != 2)
    {
        fprintf (stderr, "Usage: visualizer meshfile\n");
        exit (0);
    }

    visualizer = new Visualizer (W, H);
    visualizer->loadMesh (argv[1]);

    visualizer->initializeGL ();

    visualizer->meshEnabled = true;

    TwInit (TW_OPENGL, NULL);
    TwWindowSize (W, H);

    glutDisplayFunc (display);
    glutReshapeFunc (reshape);
    glutMouseFunc (mouse_click);
    glutMotionFunc (mouse_move);
    glutPassiveMotionFunc (mouse_move);
    glutKeyboardFunc (keyboard);
    glutSpecialFunc (special);
    TwGLUTModifiersFunc (glutGetModifiers);

    TwBar *cBar;
    cBar = TwNewBar ("Visualizer");
    TwDefine("Visualizer size='300 400'");
    TwDefine("Visualizer valueswidth=150");
    TwDefine("Visualizer color='192 255 192' text=dark ");

    TwAddVarRW(cBar, "mesh", TW_TYPE_BOOLCPP, &visualizer->meshEnabled, "");
    TwEnumVal draw_modeEV[DRAW_MODE_NUM] = { {Visualizer::SMOOTH, "Smooth"},
                                        {Visualizer::POINTS, "Points"},
                                        {Visualizer::WIRE, "Wire"},
                                        {Visualizer::FLATWIRE, "Flatwire"},
                                        {Visualizer::HIDDEN, "Hidden"},
                                        {Visualizer::FLAT, "Flat"} };
    TwType draw_modeT = TwDefineEnum("drawModeType", draw_modeEV, DRAW_MODE_NUM);
    TwAddVarRW(cBar, "DrawMode", draw_modeT, &visualizer->drawMode, " keyIncr='<' keyDecr='>'");
    TwAddVarRW(cBar, "fancyLight", TW_TYPE_BOOLCPP, &visualizer->fancyLight, "");

    TwAddSeparator (cBar, 0, 0);

    TwAddButton(cBar, "launch breadth sphere query", doTopologicQuery, NULL, "");
    TwAddButton(cBar, "launch space sphere query", doSpaceQuery, NULL, "");
    TwAddButton(cBar, "launch structure sphere query", doStructureQuery, NULL, "");

    TwAddSeparator (cBar, 0, 0);

    TwAddVarRW(cBar, "sphere breadth vertices", TW_TYPE_BOOLCPP, &visualizer->enableSphereBreadthV, "");
    TwAddVarRW(cBar, "sphere space vertices", TW_TYPE_BOOLCPP, &visualizer->enableSphereSpaceV, "");
    TwAddVarRW(cBar, "sphere structure vertices", TW_TYPE_BOOLCPP, &visualizer->enableSphereStructureV, "");
    TwAddVarRW(cBar, "picked vertex", TW_TYPE_BOOLCPP, &visualizer->enablePickV, "");

    TwAddSeparator (cBar, 0, 0);

    visualizer->setSphereRadius (5.0);
    TwAddVarCB (cBar, "scaled radius", TW_TYPE_FLOAT, setFactor, getFactor, NULL, "min=1.00 max=100.00 step=0.1");
    TwAddVarRO(cBar, "average edge", TW_TYPE_FLOAT, &visualizer->averageEdge, "");
    TwAddVarRO(cBar, "final radius", TW_TYPE_FLOAT, &visualizer->sphereRadius, "");

    glutMainLoop ();
    return 1;
}
